package johnkkk.com.obj;

import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLES32;
import android.os.Build;
import android.support.annotation.RequiresApi;

import com.graphics.element.AbsSceneNode;
import com.system.GLLog;
import com.system.Shader;
import com.tools.GLBufferTools;
import com.tools.ObjectGLConvertTools;
import com.tools.ObjectLoader;
import com.tools.SizeOf;
import com.tools.TextureTools;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;
import java.util.List;

/**
 * @Author: clm
 * @Date: 2018-11-08
 */

public class ObjModel extends AbsSceneNode {
    //网格
    private List<ObjMesh> mObjMeshes;
    private Shader mShader;
    public static class ObjMesh{
        public float[] mVertex;
        public float[] mUv;
        public float[] mNormal;
        public int[] mIndex;
        public int mIndexCount;
        //每个网格对应obj文件的一个组,每个组只会有一个纹理,所以这里只需要一个id即可
        private int mTextId;
        private int mVAO;
        private ObjectLoader.Material mMaterial;

        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
        public ObjMesh(float[] vertex, float[] uv, float[] normal, int[] index, ObjectLoader.Material material) {
            mVertex = vertex;
            mUv = uv;
            mNormal = normal;
            mIndex = index;
            mMaterial = material;
            mIndexCount = mIndex.length;
            GLLog.loge("位置数据:" + Arrays.toString(mVertex));
            GLLog.loge("纹理坐标:" + Arrays.toString(mUv));
            GLLog.loge("法线数据:" + Arrays.toString(mNormal));
            GLLog.loge("索引数据:" + Arrays.toString(mIndex));
            GLLog.loge("索引数目:" + mIndexCount);
        }

        /**
         * 生成vao
         */
        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
        public final void setup(Shader shader){
            int vao[] = new int[1];
            int vbo[] = new int[1];
            int ebo[] = new int[1];
            FloatBuffer vFB = GLBufferTools.getFloatBuffer(mVertex);
            FloatBuffer uvFB = GLBufferTools.getFloatBuffer(mUv);
            FloatBuffer nFB = GLBufferTools.getFloatBuffer(mNormal);
            IntBuffer iFB = GLBufferTools.getIntBuffer(mIndex);
            GLES32.glGenVertexArrays(1, vao, 0);
            GLES32.glGenBuffers(1, vbo, 0);
            GLES32.glGenBuffers(1, ebo, 0);

            GLES32.glBindVertexArray(vao[0]);
            GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, vbo[0]);
            GLES32.glBufferData(GLES32.GL_ARRAY_BUFFER, (vFB.limit() + uvFB.limit() + nFB.limit()) * SizeOf.S_FLOAT_SIZE, null, GLES32.GL_STATIC_DRAW);
            GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, 0, vFB.limit() * SizeOf.S_FLOAT_SIZE, vFB);
            GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, vFB.limit() * SizeOf.S_FLOAT_SIZE, uvFB.limit() * SizeOf.S_FLOAT_SIZE, uvFB);
            GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, (vFB.limit() + uvFB.limit()) * SizeOf.S_FLOAT_SIZE, nFB.limit() * SizeOf.S_FLOAT_SIZE, nFB);
            //配置属性指针
            GLES32.glVertexAttribPointer(0x001, 3, GLES32.GL_FLOAT, false, SizeOf.S_FLOAT_SIZE * 3, 0);
            GLES32.glEnableVertexAttribArray(0x001);
            GLES32.glVertexAttribPointer(0x002, 2, GLES32.GL_FLOAT, false, SizeOf.S_FLOAT_SIZE * 2, SizeOf.S_FLOAT_SIZE * vFB.limit());
            GLES32.glEnableVertexAttribArray(0x002);
            GLES32.glVertexAttribPointer(0x003, 3, GLES32.GL_FLOAT, false, SizeOf.S_FLOAT_SIZE * 3, SizeOf.S_FLOAT_SIZE * (vFB.limit() + uvFB.limit()));
            GLES32.glEnableVertexAttribArray(0x003);
            GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, 0);
            GLES32.glBindBuffer(GLES32.GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
            GLES32.glBufferData(GLES32.GL_ELEMENT_ARRAY_BUFFER, iFB.limit() * SizeOf.S_INT_SIZE, iFB, GLES32.GL_STATIC_DRAW);
            GLES32.glBindVertexArray(0);
            GLES32.glBindBuffer(GLES32.GL_ELEMENT_ARRAY_BUFFER, 0);
            mVAO = vao[0];
            //材质
            mTextId = TextureTools.genSimplerTextureAtBitmapNotRecycler(GLES32.GL_TEXTURE_2D, mMaterial.mTextures.get(ObjectLoader.Material.S_KD).mTexture)[0];
            setupShader(shader);
        }

        /**
         * 配置相应着色器
         * @param shader
         */
        public final void setupShader(Shader shader){
            GLES32.glUseProgram(shader.mShaderProgram);
            GLES32.glUniform1i(GLES32.glGetUniformLocation(shader.mShaderProgram, "text0"), 0);
            GLES32.glUniform3f(GLES32.glGetUniformLocation(shader.mShaderProgram, "light.ambientStrength"), mMaterial.mKa.r, mMaterial.mKa.g, mMaterial.mKa.b);
            GLES32.glUniform3f(GLES32.glGetUniformLocation(shader.mShaderProgram, "light.diffuseStrength"), mMaterial.mKd.r, mMaterial.mKd.g, mMaterial.mKd.b);
            GLES32.glUniform3f(GLES32.glGetUniformLocation(shader.mShaderProgram, "light.specularStrength"), mMaterial.mKs.r, mMaterial.mKs.g, mMaterial.mKs.b);
            GLES32.glUseProgram(0);
        }
    }
    public ObjModel(String name) {
        super(name);
    }
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public ObjModel(String name, String filename){
        super(name);
        mShader = new Shader("texture_base_vs.glsl", "texture_base_fs.glsl");
        GLES32.glUseProgram(mShader.mShaderProgram);
        GLES32.glUniformBlockBinding(mShader.mShaderProgram, GLES32.glGetUniformBlockIndex(mShader.mShaderProgram, "MATRIX"), 0x001);
        GLES32.glUseProgram(0);
        loadObj(filename);
    }
    /**
     * 加载obj文件
     * @param filename
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public final void loadObj(String filename){
        ObjectLoader loader = new ObjectLoader();
        loader.loadObject(filename);
        mObjMeshes = ObjectGLConvertTools.convertObjMesh2(loader);
        GLLog.loge("网格数目:" + mObjMeshes.size());
        setup(mShader);
    }

    /**
     * 用指定的着色器配置,以便进行渲染
     * @param shader
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public final void setup(Shader shader){
        for(ObjMesh mesh : mObjMeshes){
            mesh.setup(shader);
        }
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void render(float exTime) {
        super.render(exTime);
        //使用着色器
        GLES32.glUseProgram(mShader.mShaderProgram);
        for(ObjMesh mesh : mObjMeshes){
            GLES32.glActiveTexture(GLES32.GL_TEXTURE0);
            GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, mesh.mTextId);
            GLES32.glBindVertexArray(mesh.mVAO);
            GLES32.glDrawElements(GLES32.GL_TRIANGLES, mesh.mIndexCount, GLES32.GL_UNSIGNED_INT, 0);
            GLES32.glBindVertexArray(0);
            GLES32.glActiveTexture(GLES32.GL_TEXTURE0);
            GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, 0);
        }
        GLES32.glUseProgram(0);
        for(int error;((error = GLES32.glGetError())) != GLES32.GL_NO_ERROR;){
            GLLog.loge("错误:" + error);
        }
    }

    @Override
    public void update(float exTime) {
        super.update(exTime);
    }
}
